Casting a CaffeNet into a Fully Convolutional Network


In [2]:
#libs
import mxnet as mx
import os, urllib
import models
import matplotlib
import matplotlib.pyplot as plt

%matplotlib inline
matplotlib.rc("savefig", dpi=100)

import cv2
import numpy as np
from collections import namedtuple

In [12]:
model = models.create_model('caffenet')

In [13]:
Batch = namedtuple('Batch', ['data'])

def download(url,prefix=''):
    filename = prefix+url.split("/")[-1]
    if not os.path.exists(filename):
        urllib.urlretrieve(url, filename)
        
def get_image(url, show=True):
    filename = url.split("/")[-1]
    urllib.urlretrieve(url, filename)
    img = cv2.imread(filename)
    if img is None:
        print('failed to download ' + url)
    if show:
        plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
        plt.axis('off')
    return filename

In [14]:
# synset = [l.strip() for l in open('synset.txt').readlines()]
url = 'http://writm.com/wp-content/uploads/2016/08/Cat-hd-wallpapers.jpg'
img = get_image(url)



In [15]:
size = 300
img= cv2.cvtColor(cv2.imread(img), cv2.COLOR_BGR2RGB)

img = cv2.resize(img, (size, size))
img = np.swapaxes(img, 0, 2)
img = np.swapaxes(img, 1, 2) 
img = img[np.newaxis, :] 
print img.shape

batch = img


(1, 3, 300, 300)

In [16]:
model = mx.model.FeedForward.load('resnet', 1, ctx=mx.gpu(), numpy_batch_size=1)

In [5]:
# create network representation 
graph = mx.viz.plot_network(symbol=model.symbol)
# save graph
graph.format = 'png'
graph.render('ssd-net.gv', view=True)


Out[5]:
'ssd-net.gv.png'

In [18]:
# get internals from model's symbol
internals = model.symbol.get_internals()
[x for x in internals.list_outputs() if 'output' in x]


Out[18]:
['bn_data_output',
 'conv0_output',
 'bn0_output',
 'relu0_output',
 'pooling0_output',
 'stage1_unit1_bn1_output',
 'stage1_unit1_relu1_output',
 'stage1_unit1_conv1_output',
 'stage1_unit1_bn2_output',
 'stage1_unit1_relu2_output',
 'stage1_unit1_conv2_output',
 'stage1_unit1_sc_output',
 '_plus0_output',
 'stage1_unit2_bn1_output',
 'stage1_unit2_relu1_output',
 'stage1_unit2_conv1_output',
 'stage1_unit2_bn2_output',
 'stage1_unit2_relu2_output',
 'stage1_unit2_conv2_output',
 '_plus1_output',
 'stage1_unit3_bn1_output',
 'stage1_unit3_relu1_output',
 'stage1_unit3_conv1_output',
 'stage1_unit3_bn2_output',
 'stage1_unit3_relu2_output',
 'stage1_unit3_conv2_output',
 '_plus2_output',
 'stage2_unit1_bn1_output',
 'stage2_unit1_relu1_output',
 'stage2_unit1_conv1_output',
 'stage2_unit1_bn2_output',
 'stage2_unit1_relu2_output',
 'stage2_unit1_conv2_output',
 'stage2_unit1_sc_output',
 '_plus3_output',
 'stage2_unit2_bn1_output',
 'stage2_unit2_relu1_output',
 'stage2_unit2_conv1_output',
 'stage2_unit2_bn2_output',
 'stage2_unit2_relu2_output',
 'stage2_unit2_conv2_output',
 '_plus4_output',
 'stage2_unit3_bn1_output',
 'stage2_unit3_relu1_output',
 'stage2_unit3_conv1_output',
 'stage2_unit3_bn2_output',
 'stage2_unit3_relu2_output',
 'stage2_unit3_conv2_output',
 '_plus5_output',
 'stage2_unit4_bn1_output',
 'stage2_unit4_relu1_output',
 'stage2_unit4_conv1_output',
 'stage2_unit4_bn2_output',
 'stage2_unit4_relu2_output',
 'stage2_unit4_conv2_output',
 '_plus6_output',
 'stage3_unit1_bn1_output',
 'stage3_unit1_relu1_output',
 'stage3_unit1_conv1_output',
 'stage3_unit1_bn2_output',
 'stage3_unit1_relu2_output',
 'stage3_unit1_conv2_output',
 'stage3_unit1_sc_output',
 '_plus7_output',
 'stage3_unit2_bn1_output',
 'stage3_unit2_relu1_output',
 'stage3_unit2_conv1_output',
 'stage3_unit2_bn2_output',
 'stage3_unit2_relu2_output',
 'stage3_unit2_conv2_output',
 '_plus8_output',
 'stage3_unit3_bn1_output',
 'stage3_unit3_relu1_output',
 'stage3_unit3_conv1_output',
 'stage3_unit3_bn2_output',
 'stage3_unit3_relu2_output',
 'stage3_unit3_conv2_output',
 '_plus9_output',
 'stage3_unit4_bn1_output',
 'stage3_unit4_relu1_output',
 'stage3_unit4_conv1_output',
 'stage3_unit4_bn2_output',
 'stage3_unit4_relu2_output',
 'stage3_unit4_conv2_output',
 '_plus10_output',
 'stage3_unit5_bn1_output',
 'stage3_unit5_relu1_output',
 'stage3_unit5_conv1_output',
 'stage3_unit5_bn2_output',
 'stage3_unit5_relu2_output',
 'stage3_unit5_conv2_output',
 '_plus11_output',
 'stage3_unit6_bn1_output',
 'stage3_unit6_relu1_output',
 'stage3_unit6_conv1_output',
 'stage3_unit6_bn2_output',
 'stage3_unit6_relu2_output',
 'stage3_unit6_conv2_output',
 '_plus12_output',
 'stage4_unit1_bn1_output',
 'stage4_unit1_relu1_output',
 'stage4_unit1_conv1_output',
 'stage4_unit1_bn2_output',
 'stage4_unit1_relu2_output',
 'stage4_unit1_conv2_output',
 'stage4_unit1_sc_output',
 '_plus13_output',
 'stage4_unit2_bn1_output',
 'stage4_unit2_relu1_output',
 'stage4_unit2_conv1_output',
 'stage4_unit2_bn2_output',
 'stage4_unit2_relu2_output',
 'stage4_unit2_conv2_output',
 '_plus14_output',
 'stage4_unit3_bn1_output',
 'stage4_unit3_relu1_output',
 'stage4_unit3_conv1_output',
 'stage4_unit3_bn2_output',
 'stage4_unit3_relu2_output',
 'stage4_unit3_conv2_output',
 '_plus15_output',
 'bn1_output',
 'relu1_output',
 'pool1_output',
 'flatten0_output',
 'fc1_output',
 'softmax_output']

In [10]:
# # get feature layer symbol out of internals
fea_symbol = internals['flatten0_output']

# Make a new model by using an internal symbol. We can reuse all parameters from model we trained before
# In this case, we must set ```allow_extra_params``` to True
# Because we don't need params from FullyConnected symbol

feature_extractor = mx.model.FeedForward(ctx=mx.gpu(), 
                                         symbol=fea_symbol,
                                         numpy_batch_size=1,
                                         arg_params=model.arg_params,
                                         aux_params=model.aux_params,
                                         allow_extra_params=True)
# predict feature
layer_info = feature_extractor.predict(batch)
m = layer_info.reshape(layer_info.shape[1], layer_info.shape[2], layer_info.shape[3]).argmax(axis=0)

plt.figure(figsize=(5,5))
plt.title(str(layer_info.shape))
plt.imshow(m)
plt.show()



In [19]:
for i in internals.list_outputs():
    if 'output' in i:
        # # get feature layer symbol out of internals
        fea_symbol = internals[i]

        # Make a new model by using an internal symbol. We can reuse all parameters from model we trained before
        # In this case, we must set ```allow_extra_params``` to True
        # Because we don't need params from FullyConnected symbol
        feature_extractor = mx.model.FeedForward(ctx=mx.gpu(), 
                                                 symbol=fea_symbol,
                                                 numpy_batch_size=1,
                                                 arg_params=model.arg_params,
                                                 aux_params=model.aux_params,
                                                 allow_extra_params=True)
        # predict feature
        layer_info = feature_extractor.predict(batch)
        print(i, layer_info.shape)
#         m = layer_info.reshape(layer_info.shape[1], layer_info.shape[2], layer_info.shape[3])
#         for j in range(layer_info.shape[1]):
#             a = m[j, :, :].reshape(layer_info.shape[2], layer_info.shape[3])
#             plt.figure(figsize=(5,5))
#             plt.title(i+str(layer_info.shape))
#             plt.imshow(a)
#             plt.show()


('bn_data_output', (1, 3, 300, 300))
('conv0_output', (1, 64, 150, 150))
('bn0_output', (1, 64, 150, 150))
('relu0_output', (1, 64, 150, 150))
('pooling0_output', (1, 64, 75, 75))
('stage1_unit1_bn1_output', (1, 64, 75, 75))
('stage1_unit1_relu1_output', (1, 64, 75, 75))
('stage1_unit1_conv1_output', (1, 64, 75, 75))
('stage1_unit1_bn2_output', (1, 64, 75, 75))
('stage1_unit1_relu2_output', (1, 64, 75, 75))
('stage1_unit1_conv2_output', (1, 64, 75, 75))
('stage1_unit1_sc_output', (1, 64, 75, 75))
('_plus0_output', (1, 64, 75, 75))
('stage1_unit2_bn1_output', (1, 64, 75, 75))
('stage1_unit2_relu1_output', (1, 64, 75, 75))
('stage1_unit2_conv1_output', (1, 64, 75, 75))
('stage1_unit2_bn2_output', (1, 64, 75, 75))
('stage1_unit2_relu2_output', (1, 64, 75, 75))
('stage1_unit2_conv2_output', (1, 64, 75, 75))
('_plus1_output', (1, 64, 75, 75))
('stage1_unit3_bn1_output', (1, 64, 75, 75))
('stage1_unit3_relu1_output', (1, 64, 75, 75))
('stage1_unit3_conv1_output', (1, 64, 75, 75))
('stage1_unit3_bn2_output', (1, 64, 75, 75))
('stage1_unit3_relu2_output', (1, 64, 75, 75))
('stage1_unit3_conv2_output', (1, 64, 75, 75))
('_plus2_output', (1, 64, 75, 75))
('stage2_unit1_bn1_output', (1, 64, 75, 75))
('stage2_unit1_relu1_output', (1, 64, 75, 75))
('stage2_unit1_conv1_output', (1, 128, 38, 38))
('stage2_unit1_bn2_output', (1, 128, 38, 38))
('stage2_unit1_relu2_output', (1, 128, 38, 38))
('stage2_unit1_conv2_output', (1, 128, 38, 38))
('stage2_unit1_sc_output', (1, 128, 38, 38))
('_plus3_output', (1, 128, 38, 38))
('stage2_unit2_bn1_output', (1, 128, 38, 38))
('stage2_unit2_relu1_output', (1, 128, 38, 38))
('stage2_unit2_conv1_output', (1, 128, 38, 38))
('stage2_unit2_bn2_output', (1, 128, 38, 38))
('stage2_unit2_relu2_output', (1, 128, 38, 38))
('stage2_unit2_conv2_output', (1, 128, 38, 38))
('_plus4_output', (1, 128, 38, 38))
('stage2_unit3_bn1_output', (1, 128, 38, 38))
('stage2_unit3_relu1_output', (1, 128, 38, 38))
('stage2_unit3_conv1_output', (1, 128, 38, 38))
('stage2_unit3_bn2_output', (1, 128, 38, 38))
('stage2_unit3_relu2_output', (1, 128, 38, 38))
('stage2_unit3_conv2_output', (1, 128, 38, 38))
('_plus5_output', (1, 128, 38, 38))
('stage2_unit4_bn1_output', (1, 128, 38, 38))
('stage2_unit4_relu1_output', (1, 128, 38, 38))
('stage2_unit4_conv1_output', (1, 128, 38, 38))
('stage2_unit4_bn2_output', (1, 128, 38, 38))
('stage2_unit4_relu2_output', (1, 128, 38, 38))
('stage2_unit4_conv2_output', (1, 128, 38, 38))
('_plus6_output', (1, 128, 38, 38))
('stage3_unit1_bn1_output', (1, 128, 38, 38))
('stage3_unit1_relu1_output', (1, 128, 38, 38))
('stage3_unit1_conv1_output', (1, 256, 19, 19))
('stage3_unit1_bn2_output', (1, 256, 19, 19))
('stage3_unit1_relu2_output', (1, 256, 19, 19))
('stage3_unit1_conv2_output', (1, 256, 19, 19))
('stage3_unit1_sc_output', (1, 256, 19, 19))
('_plus7_output', (1, 256, 19, 19))
('stage3_unit2_bn1_output', (1, 256, 19, 19))
('stage3_unit2_relu1_output', (1, 256, 19, 19))
('stage3_unit2_conv1_output', (1, 256, 19, 19))
('stage3_unit2_bn2_output', (1, 256, 19, 19))
('stage3_unit2_relu2_output', (1, 256, 19, 19))
('stage3_unit2_conv2_output', (1, 256, 19, 19))
('_plus8_output', (1, 256, 19, 19))
('stage3_unit3_bn1_output', (1, 256, 19, 19))
('stage3_unit3_relu1_output', (1, 256, 19, 19))
('stage3_unit3_conv1_output', (1, 256, 19, 19))
('stage3_unit3_bn2_output', (1, 256, 19, 19))
('stage3_unit3_relu2_output', (1, 256, 19, 19))
('stage3_unit3_conv2_output', (1, 256, 19, 19))
('_plus9_output', (1, 256, 19, 19))
('stage3_unit4_bn1_output', (1, 256, 19, 19))
('stage3_unit4_relu1_output', (1, 256, 19, 19))
('stage3_unit4_conv1_output', (1, 256, 19, 19))
('stage3_unit4_bn2_output', (1, 256, 19, 19))
('stage3_unit4_relu2_output', (1, 256, 19, 19))
('stage3_unit4_conv2_output', (1, 256, 19, 19))
('_plus10_output', (1, 256, 19, 19))
('stage3_unit5_bn1_output', (1, 256, 19, 19))
('stage3_unit5_relu1_output', (1, 256, 19, 19))
('stage3_unit5_conv1_output', (1, 256, 19, 19))
('stage3_unit5_bn2_output', (1, 256, 19, 19))
('stage3_unit5_relu2_output', (1, 256, 19, 19))
('stage3_unit5_conv2_output', (1, 256, 19, 19))
('_plus11_output', (1, 256, 19, 19))
('stage3_unit6_bn1_output', (1, 256, 19, 19))
('stage3_unit6_relu1_output', (1, 256, 19, 19))
('stage3_unit6_conv1_output', (1, 256, 19, 19))
('stage3_unit6_bn2_output', (1, 256, 19, 19))
('stage3_unit6_relu2_output', (1, 256, 19, 19))
('stage3_unit6_conv2_output', (1, 256, 19, 19))
('_plus12_output', (1, 256, 19, 19))
('stage4_unit1_bn1_output', (1, 256, 19, 19))
('stage4_unit1_relu1_output', (1, 256, 19, 19))
('stage4_unit1_conv1_output', (1, 512, 10, 10))
('stage4_unit1_bn2_output', (1, 512, 10, 10))
('stage4_unit1_relu2_output', (1, 512, 10, 10))
('stage4_unit1_conv2_output', (1, 512, 10, 10))
('stage4_unit1_sc_output', (1, 512, 10, 10))
('_plus13_output', (1, 512, 10, 10))
('stage4_unit2_bn1_output', (1, 512, 10, 10))
('stage4_unit2_relu1_output', (1, 512, 10, 10))
('stage4_unit2_conv1_output', (1, 512, 10, 10))
('stage4_unit2_bn2_output', (1, 512, 10, 10))
('stage4_unit2_relu2_output', (1, 512, 10, 10))
('stage4_unit2_conv2_output', (1, 512, 10, 10))
('_plus14_output', (1, 512, 10, 10))
('stage4_unit3_bn1_output', (1, 512, 10, 10))
('stage4_unit3_relu1_output', (1, 512, 10, 10))
('stage4_unit3_conv1_output', (1, 512, 10, 10))
('stage4_unit3_bn2_output', (1, 512, 10, 10))
('stage4_unit3_relu2_output', (1, 512, 10, 10))
('stage4_unit3_conv2_output', (1, 512, 10, 10))
('_plus15_output', (1, 512, 10, 10))
('bn1_output', (1, 512, 10, 10))
('relu1_output', (1, 512, 10, 10))
('pool1_output', (1, 512, 1, 1))
('flatten0_output', (1, 512))
('fc1_output', (1, 1000))
('softmax_output', (1, 1000))

In [22]:
# # get feature layer symbol out of internals
fea_symbol = internals['conv4_output']

# Make a new model by using an internal symbol. We can reuse all parameters from model we trained before
# In this case, we must set ```allow_extra_params``` to True
# Because we don't need params from FullyConnected symbol
feature_extractor = mx.model.FeedForward(ctx=mx.gpu(), 
                                         symbol=fea_symbol,
                                         numpy_batch_size=1,
                                         arg_params=model.arg_params,
                                         aux_params=model.aux_params,
                                         allow_extra_params=True)
# predict feature
layer_info = feature_extractor.forward(batch)
m = layer_info.reshape(layer_info.shape[1], layer_info.shape[2], layer_info.shape[3]).argmax(axis=0)
plt.figure(figsize=(3,3))
plt.title(+str(layer_info.shape))
plt.imshow(m)
plt.show()


---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-22-a301bf0d9241> in <module>()
      1 # # get feature layer symbol out of internals
----> 2 fea_symbol = internals['conv4_output']
      3 
      4 # Make a new model by using an internal symbol. We can reuse all parameters from model we trained before
      5 # In this case, we must set ```allow_extra_params``` to True

/home/home/mxnet-ssd/mxnet/python/mxnet/symbol.pyc in __getitem__(self, index)
    199                     idx = i
    200             if idx is None:
--> 201                 raise ValueError('Cannot find output that matches name \"%s\"' % index)
    202             index = idx
    203         if not isinstance(index, int):

ValueError: Cannot find output that matches name "conv4_output"